home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 51 / Amiga Format CD51 (2000-03-10)(Future Publishing)(GB)[!][issue 2000-04].iso / -in_the_mag- / workbench / term_4.8 / extras / source / term-source.lha / Launch.c < prev    next >
C/C++ Source or Header  |  1997-10-03  |  11KB  |  526 lines

  1. /*
  2. **    Launch.c
  3. **
  4. **    Routines to launch programs, ARexx scripts, etc.
  5. **
  6. **    Copyright © 1990-1997 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. **
  9. **    :ts=4
  10. */
  11.  
  12. #ifndef _GLOBAL_H
  13. #include "Global.h"
  14. #endif
  15.  
  16.     /* Local data. */
  17.  
  18. STATIC struct SignalSemaphore    LaunchSemaphore;
  19. STATIC LONG                        LaunchCounter;
  20.  
  21. STATIC BOOL
  22. OpenStreams(STRPTR StreamName,BPTR *InputStream,BPTR *OutputStream)
  23. {
  24.     BPTR Stream;
  25.  
  26.         /* Open the output stream. */
  27.  
  28.     if(Stream = Open(StreamName,MODE_NEWFILE))
  29.     {
  30.             /* Check if the stream is not "NIL:" and if it is interactive. */
  31.  
  32.         if(GoodStream(Stream))
  33.         {
  34.             *InputStream    = Stream;
  35.             *OutputStream    = NULL;
  36.         }
  37.         else
  38.         {
  39.             *InputStream    = Open("NIL:",MODE_NEWFILE);
  40.             *OutputStream    = Stream;
  41.         }
  42.  
  43.         if(*InputStream)
  44.             return(TRUE);
  45.         else
  46.         {
  47.             LONG Error = IoErr();
  48.  
  49.             Close(Stream);
  50.  
  51.             SetIoErr(Error);
  52.         }
  53.     }
  54.  
  55.     return(FALSE);
  56. }
  57.  
  58.     /* LaunchEntry(VOID):
  59.      *
  60.      *    Entry point of the routine that handles the workload.
  61.      */
  62.  
  63. STATIC VOID SAVE_DS
  64. LaunchEntry(VOID)
  65. {
  66.     LaunchMsg        *Startup;
  67.     struct MsgPort    *CurrentPort;
  68.     BPTR             InputStream,OutputStream;
  69.     struct MsgPort    *GlobalRexxPort;
  70.  
  71.         /* Grab the startup packet. */
  72.  
  73.     CurrentPort = &((struct Process *)FindTask(NULL))->pr_MsgPort;
  74.     WaitPort(CurrentPort);
  75.     Startup = (LaunchMsg *)GetMsg(CurrentPort);
  76.  
  77.         /* Increment the launch counter. */
  78.  
  79.     ObtainSemaphore(&LaunchSemaphore);
  80.     LaunchCounter++;
  81.     ReleaseSemaphore(&LaunchSemaphore);
  82.  
  83.         /* Open the streams. */
  84.  
  85.     InputStream = OutputStream = NULL;
  86.  
  87.     if(!OpenStreams(Startup->Message.mn_Node.ln_Name,&InputStream,&OutputStream))
  88.         Startup->Result2 = IoErr();
  89.     else
  90.     {
  91.         if(!OutputStream)
  92.         {
  93.             SelectInput(InputStream);
  94.  
  95.             SetConsoleTask(((struct FileHandle *)BADDR(InputStream))->fh_Type);
  96.  
  97.             if(!(OutputStream = Open("CONSOLE:",MODE_NEWFILE)))
  98.                 Startup->Result2 = IoErr();
  99.         }
  100.     }
  101.  
  102.     if(InputStream && OutputStream)
  103.     {
  104.         SelectOutput(OutputStream);
  105.  
  106.         Forbid();
  107.  
  108.             /* Try to find the global Rexx port. */
  109.  
  110.         if(!(GlobalRexxPort = FindPort(RXSDIR)))
  111.             Startup->Result2 = ERROR_OBJECT_NOT_FOUND;
  112.         else
  113.         {
  114.             struct MsgPort     SinglePort;
  115.             struct RexxMsg    *RexxMsg;
  116.  
  117.                 /* Set up our local msgport. */
  118.  
  119.             InitSinglePort(&SinglePort);
  120.  
  121.                 /* Create a message for Rexx. */
  122.  
  123.             if(RexxMsg = CreateRexxMsg(&SinglePort,"term",RexxPortName))
  124.             {
  125.                     /* And put in the command to execute. */
  126.  
  127.                 if(RexxMsg->rm_Args[0] = CreateArgstring(Startup->Command,strlen(Startup->Command)))
  128.                 {
  129.                         /* Flag the message as a command to be executed. */
  130.  
  131.                     RexxMsg->rm_Action = RXCOMM;
  132.  
  133.                         /* In case it's just a single string, flag it as being such. */
  134.  
  135.                     if(Startup->Type == LAUNCH_RexxString)
  136.                         RexxMsg->rm_Action |= RXFF_STRING;
  137.  
  138.                         /* Clear the port mask. */
  139.  
  140.                     SetSignal(0,SIGF_SINGLE);
  141.  
  142.                         /* Send the message and wait for it to return.
  143.                          * Notice that after the WaitPort() call we
  144.                          * won't call GetMsg() since we don't need the
  145.                          * msgport any more and don't expect more than
  146.                          * one message to end up here.
  147.                          */
  148.  
  149.                     PutMsg(GlobalRexxPort,(struct Message *)RexxMsg);
  150.                     WaitPort(&SinglePort);
  151.  
  152.                         /* Store the command result. */
  153.  
  154.                     Startup->Result        = RexxMsg->rm_Result1;
  155.                     Startup->Result2    = RexxMsg->rm_Result2;
  156.  
  157.                         /* And clean up the rest. */
  158.  
  159.                     DeleteArgstring(RexxMsg->rm_Args[0]);
  160.                 }
  161.                 else
  162.                     Startup->Result2 = ERROR_NO_FREE_STORE;
  163.  
  164.                 DeleteRexxMsg(RexxMsg);
  165.             }
  166.             else
  167.                 Startup->Result2 = ERROR_NO_FREE_STORE;
  168.         }
  169.  
  170.         Permit();
  171.     }
  172.  
  173.         /* Call the cleanup routine if any. */
  174.  
  175.     if(Startup->Cleanup)
  176.         (*Startup->Cleanup)(Startup);
  177.  
  178.         /* Close the streams. */
  179.  
  180.     if(InputStream)
  181.         Close(InputStream);
  182.  
  183.     if(OutputStream)
  184.         Close(OutputStream);
  185.  
  186.         /* Decrement the launch counter and disable
  187.          * multitasking for a short while.
  188.          */
  189.  
  190.     ObtainSemaphore(&LaunchSemaphore);
  191.  
  192.     LaunchCounter--;
  193.  
  194.     Forbid();
  195.  
  196.         /* Check if we should wake up the process that
  197.          * created us. If not, dispose of the startup
  198.          * message.
  199.          */
  200.  
  201.     if(Startup->Message.mn_ReplyPort != NULL)
  202.         ReplyMsg((struct Message *)Startup);
  203.     else
  204.         DeleteLaunchMsg(Startup);
  205.  
  206.         /* Release the launch counter semaphore and exit. */
  207.  
  208.     ReleaseSemaphore(&LaunchSemaphore);
  209. }
  210.  
  211.     /* CreateLaunchMsg(WORD Type,STRPTR Command,struct RexxPkt *RexxPkt,LAUNCHCLEANUP Cleanup):
  212.      *
  213.      *    This sets up a launch message with given parameters.
  214.      */
  215.  
  216. STATIC LaunchMsg *
  217. CreateLaunchMsg(WORD Type,STRPTR Command,struct RexxPkt *RexxPkt,LAUNCHCLEANUP Cleanup)
  218. {
  219.     LaunchMsg *Startup;
  220.  
  221.         /* Allocate memory for the data structure and initialize it. */
  222.  
  223.     if(Startup = (LaunchMsg *)AllocVecPooled(sizeof(LaunchMsg) + strlen(Command) + 1,MEMF_ANY|MEMF_CLEAR))
  224.     {
  225.         Startup->Message.mn_Length    = sizeof(LaunchMsg) + strlen(Command);
  226.         Startup->Type                = Type;
  227.         Startup->RexxPkt            = RexxPkt;
  228.         Startup->Cleanup            = Cleanup;
  229.  
  230.         strcpy(Startup->Command,Command);
  231.     }
  232.  
  233.     return(Startup);
  234. }
  235.  
  236.     /* DeleteLaunchMsg(LaunchMsg *Startup):
  237.      *
  238.      *    Releases all the memory allocated for the launch message.
  239.      */
  240.  
  241. VOID
  242. DeleteLaunchMsg(LaunchMsg *Startup)
  243. {
  244.     if(Startup->Message.mn_Node.ln_Name)
  245.         FreeVecPooled(Startup->Message.mn_Node.ln_Name);
  246.  
  247.     FreeVecPooled(Startup);
  248. }
  249.  
  250.     /* CreateRexxCmdLaunchMsg():
  251.      *
  252.      *    Creates a special type of launch message for use with Rexx commands.
  253.      */
  254.  
  255. LaunchMsg *
  256. CreateRexxCmdLaunchMsg(STRPTR RexxCmd,struct RexxPkt *RexxPkt,LAUNCHCLEANUP Cleanup)
  257. {
  258.     return(CreateLaunchMsg(LAUNCH_RexxCmd,RexxCmd,RexxPkt,Cleanup));
  259. }
  260.  
  261.     /* CreateProgramLaunchMsg():
  262.      *
  263.      *    Creates a special type of launch message for use with AmigaDOS commands.
  264.      */
  265.  
  266. LaunchMsg *
  267. CreateProgramLaunchMsg(STRPTR Program,LAUNCHCLEANUP Cleanup)
  268. {
  269.     return(CreateLaunchMsg(LAUNCH_Program,Program,NULL,Cleanup));
  270. }
  271.  
  272.     /* LaunchSomething(STRPTR OriginalStreamName,BOOL Synchronous,LaunchMsg *Startup):
  273.      *
  274.      *    Launch a program either in synchronous or asynchronous fashion, using
  275.      *    a given output stream. If no stream name is given, "NIL:" will be used.
  276.      */
  277.  
  278. LONG
  279. LaunchSomething(STRPTR OriginalStreamName,BOOL Synchronous,LaunchMsg *Startup)
  280. {
  281.     BPTR InputStream,OutputStream;
  282.     BOOL InsertScreenName;
  283.     LONG Result,Error;
  284.     STRPTR StreamName;
  285.     LONG i,Head;
  286.  
  287.         /* Did we get a name? If not, use "NIL:". */
  288.  
  289.     if(!OriginalStreamName)
  290.         OriginalStreamName = "NIL:";
  291.     else
  292.     {
  293.             /* Is the string empty? If so, use "NIL:". */
  294.  
  295.         if(!OriginalStreamName[0])
  296.             OriginalStreamName = "NIL:";
  297.     }
  298.  
  299.         /* Scan the stream name for "%s" which will be replaced by the
  300.          * name of the public screen `term' is using.
  301.          */
  302.  
  303.     for(i = 0, InsertScreenName = FALSE, Head = 0 ; i < strlen(OriginalStreamName) - 1 ; i++)
  304.     {
  305.         if(OriginalStreamName[i] == '%' && OriginalStreamName[i+1] == 's')
  306.         {
  307.             Head = i;
  308.  
  309.             InsertScreenName = TRUE;
  310.             break;
  311.         }
  312.     }
  313.  
  314.         /* Should we insert a public screen name somewhere? */
  315.  
  316.     if(InsertScreenName)
  317.     {
  318.         UBYTE ScreenName[MAXPUBSCREENNAME + 1];
  319.  
  320.             /* Get the name of the current default public screen. */
  321.  
  322.         GetDefaultPubScreen(ScreenName);
  323.  
  324.             /* If the screen `term' has its main window on is on a
  325.              * public screen, get the name of this screen. Otherwise,
  326.              * don't touch the buffer contents.
  327.              */
  328.  
  329.         if(Window)
  330.             GetPubScreenName(Window->WScreen,ScreenName);
  331.  
  332.             /* Make room for the screen name. */
  333.  
  334.         if(!(StreamName = (STRPTR)AllocVecPooled(strlen(ScreenName) + strlen(OriginalStreamName) - 1,MEMF_ANY)))
  335.         {
  336.             SetIoErr(ERROR_NO_FREE_STORE);
  337.  
  338.             return(FALSE);
  339.         }
  340.  
  341.             /* Insert the screen name into the stream name. */
  342.  
  343.         if(Head > 0)
  344.             strncpy(StreamName,OriginalStreamName,Head);
  345.  
  346.         StreamName[Head] = '\0';
  347.  
  348.         strcat(StreamName,ScreenName);
  349.         strcat(StreamName,&OriginalStreamName[Head + 2]);
  350.     }
  351.     else
  352.         StreamName = OriginalStreamName;
  353.  
  354.         /* Reset these. */
  355.  
  356.     Result = Error = 0;
  357.  
  358.     InputStream = OutputStream = NULL;
  359.  
  360.     if(Startup->Type == LAUNCH_Program)
  361.     {
  362.         if(!OpenStreams(StreamName,&InputStream,&OutputStream))
  363.             Error = IoErr();
  364.         else
  365.         {
  366.             if(Result = SystemTags(Startup->Command,
  367.                 SYS_Input,        InputStream,
  368.                 SYS_Output,        OutputStream,
  369.                 SYS_Asynch,        Synchronous == FALSE,
  370.                 SYS_UserShell,    TRUE,
  371.                 NP_StackSize,    8000,
  372.             TAG_DONE))
  373.                 Error = IoErr();
  374.  
  375.                 /* These will be closed when the program
  376.                  * launched will exit.
  377.                  */
  378.  
  379.             if(Synchronous == FALSE)
  380.                 InputStream = OutputStream = NULL;
  381.         }
  382.  
  383.         Startup->Result        = Result;
  384.         Startup->Result2    = Error;
  385.     }
  386.     else
  387.     {
  388.         if(!(Startup->Message.mn_Node.ln_Name = (char *)AllocVecPooled(strlen(StreamName) + 1,MEMF_ANY)))
  389.             Error = IoErr();
  390.         else
  391.         {
  392.                 /* The default process launch tags. */
  393.  
  394.             STATIC struct TagItem DefaultTags[] =
  395.             {
  396.                 NP_Entry,        (ULONG)LaunchEntry,
  397.                 NP_StackSize,    8000,
  398.                 NP_Name,        (ULONG)"term Child Process",
  399.                 NP_Cli,            TRUE,
  400.                 NP_Input,        NULL,
  401.                 NP_Output,        NULL,
  402.                 NP_CloseInput,    FALSE,
  403.                 NP_CloseOutput,    FALSE,
  404.  
  405.                 TAG_DONE
  406.             };
  407.  
  408.             struct Process *Child;
  409.  
  410.                 /* Keep the stream name. */
  411.  
  412.             strcpy(Startup->Message.mn_Node.ln_Name,StreamName);
  413.  
  414.                 /* Launch the child process. */
  415.  
  416.             if(!(Child = CreateNewProc(DefaultTags)))
  417.             {
  418.                 Result    = RETURN_FAIL;
  419.                 Error    = IoErr();
  420.             }
  421.             else
  422.             {
  423.                     /* If the command is to be executed in asynchronous
  424.                      * fashion, just send the message. The child process
  425.                      * will clean up all on its own.
  426.                      */
  427.  
  428.                 if(Synchronous == FALSE)
  429.                     PutMsg(&Child->pr_MsgPort,(struct Message *)Startup);
  430.                 else
  431.                 {
  432.                     struct MsgPort SinglePort;
  433.  
  434.                         /* Set up the local msgport. */
  435.  
  436.                     InitSinglePort(&SinglePort);
  437.  
  438.                         /* Clear the port signal. */
  439.  
  440.                     SetSignal(0,SIGF_SINGLE);
  441.  
  442.                         /* Fill in the reply port. */
  443.  
  444.                     Startup->Message.mn_ReplyPort = &SinglePort;
  445.  
  446.                         /* Send the startup message and wait for the
  447.                          * reply. Note that we don't GetMsg() the
  448.                          * message we sent since the local msgport
  449.                          * will be discarded anyway.
  450.                          */
  451.  
  452.                     PutMsg(&Child->pr_MsgPort,(struct Message *)Startup);
  453.                     WaitPort(&SinglePort);
  454.  
  455.                         /* Copy the result data. */
  456.  
  457.                     Result    = Startup->Result;
  458.                     Error    = Startup->Result2;
  459.                 }
  460.             }
  461.         }
  462.     }
  463.  
  464.         /* Do the cleanup. */
  465.  
  466.     if(Synchronous)
  467.     {
  468.         Startup->Result        = Result;
  469.         Startup->Result2    = Error;
  470.     }
  471.  
  472.     if(Startup->Cleanup)
  473.         (*Startup->Cleanup)(Startup);
  474.  
  475.     if(Synchronous)
  476.         DeleteLaunchMsg(Startup);
  477.  
  478.         /* Close the streams still open. */
  479.  
  480.     if(InputStream)
  481.         Close(InputStream);
  482.  
  483.     if(OutputStream)
  484.         Close(OutputStream);
  485.  
  486.         /* If we had allocated a new stream name, release the memory. */
  487.  
  488.     if(StreamName != OriginalStreamName)
  489.         FreeVecPooled(StreamName);
  490.  
  491.     SetIoErr(Error);
  492.  
  493.     return(Result);
  494. }
  495.  
  496.     /* LaunchSetup():
  497.      *
  498.      *    Does the setup operation for the launch procedure.
  499.      */
  500.  
  501. VOID
  502. LaunchSetup()
  503. {
  504.     InitSemaphore(&LaunchSemaphore);
  505. }
  506.  
  507.     /* GetLaunchCounter():
  508.      *
  509.      *    Returns the number of processes launched that haven't
  510.      *    returned already.
  511.      */
  512.  
  513. LONG
  514. GetLaunchCounter()
  515. {
  516.     LONG Counter;
  517.  
  518.     SafeObtainSemaphoreShared(&LaunchSemaphore);
  519.  
  520.     Counter = LaunchCounter;
  521.  
  522.     ReleaseSemaphore(&LaunchSemaphore);
  523.  
  524.     return(Counter);
  525. }
  526.